package cloud.shyidong.auth.service.impl;

import cloud.shyidong.auth.service.AuthService;
import cloud.shyidong.cache.service.CacheService;
import cloud.shyidong.core.Result;
import cloud.shyidong.core.constant.StatusConstant;
import cloud.shyidong.core.constant.TokenConstant;
import cloud.shyidong.core.constant.UserTypeConstant;
import cloud.shyidong.core.exception.BusinessException;
import cloud.shyidong.core.util.CollectionUtils;
import cloud.shyidong.core.util.MD5Utils;
import cloud.shyidong.core.util.ObjectUtils;
import cloud.shyidong.system.dao.*;
import cloud.shyidong.system.entity.*;
import cloud.shyidong.system.request.LoginRequest;
import cloud.shyidong.tenant.dao.*;
import cloud.shyidong.tenant.entity.*;
import cloud.shyidong.tenant.request.TenantLoginRequest;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description TODO
 * @Author syd
 * @Date 2023/10/19
 */
@Service
public class AuthServiceImpl implements AuthService {
    
    private SystemUserDao systemUserDao;
    
    private SystemMenuDao systemMenuDao;
    
    private SystemFunctionDao systemFunctionDao;
    
    private SystemUserRoleDao systemUserRoleDao;
    
    private SystemRoleMenuDao systemRoleMenuDao;
    
    private SystemRoleFunctionDao systemRoleFunctionDao;
    
    private TenantMenuDao tenantMenuDao;
    
    private TenantFunctionDao tenantFunctionDao;
    
    private TenantUserDao tenantUserDao;
    
    private TenantTenantDao tenantTenantDao;
    
    private TenantTenantMenuDao tenantTenantMenuDao;
    
    private TenantTenantFunctionDao tenantTenantFunctionDao;
    
    private CacheService cacheService;
    
    @Autowired
    public void setSystemUserDao(SystemUserDao systemUserDao) {
        this.systemUserDao = systemUserDao;
    }
    
    @Autowired
    public void setSystemMenuDao(SystemMenuDao systemMenuDao) {
        this.systemMenuDao = systemMenuDao;
    }
    
    @Autowired
    public void setSystemFunctionDao(SystemFunctionDao systemFunctionDao) {
        this.systemFunctionDao = systemFunctionDao;
    }
    
    @Autowired
    public void setSystemUserRoleDao(SystemUserRoleDao systemUserRoleDao) {
        this.systemUserRoleDao = systemUserRoleDao;
    }
    
    @Autowired
    public void setSystemRoleMenuDao(SystemRoleMenuDao systemRoleMenuDao) {
        this.systemRoleMenuDao = systemRoleMenuDao;
    }
    
    @Autowired
    public void setSystemRoleFunctionDao(SystemRoleFunctionDao systemRoleFunctionDao) {
        this.systemRoleFunctionDao = systemRoleFunctionDao;
    }
    
    @Autowired
    public void setTenantMenuDao(TenantMenuDao tenantMenuDao) {
        this.tenantMenuDao = tenantMenuDao;
    }
    
    @Autowired
    public void setTenantFunctionDao(TenantFunctionDao tenantFunctionDao) {
        this.tenantFunctionDao = tenantFunctionDao;
    }
    
    @Autowired
    public void setTenantUserDao(TenantUserDao tenantUserDao) {
        this.tenantUserDao = tenantUserDao;
    }
    
    @Autowired
    public void setTenantTenantDao(TenantTenantDao tenantTenantDao) {
        this.tenantTenantDao = tenantTenantDao;
    }
    
    @Autowired
    public void setTenantTenantMenuDao(TenantTenantMenuDao tenantTenantMenuDao) {
        this.tenantTenantMenuDao = tenantTenantMenuDao;
    }
    
    @Autowired
    public void setTenantTenantFunctionDao(TenantTenantFunctionDao tenantTenantFunctionDao) {
        this.tenantTenantFunctionDao = tenantTenantFunctionDao;
    }
    
    @Autowired
    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result adminLogin(LoginRequest loginRequest) {
        
        //验证登录名称
        List<SystemUserEntity> systemUserEntities = systemUserDao.selectList(new QueryWrapper<SystemUserEntity>().eq("username", loginRequest.getUsername()));
        if (CollectionUtils.isEmpty(systemUserEntities)) {
            throw BusinessException.from("登录名称不存在或登录密码错误");
        }
        
        SystemUserEntity systemUserEntity = systemUserEntities.get(0);
        
        //验证登录密码
        if (!systemUserEntity.getPassword().equals(MD5Utils.md5Hex(loginRequest.getPassword()))) {
            throw BusinessException.from("登录名称不存在或登录密码错误");
        }
        //验证状态
        if (systemUserEntity.getStatus().intValue() == StatusConstant.DISABLE) {
            throw BusinessException.from("登录名称不存在或登录密码错误");
        }
        
        //查询登录用户拥有的菜单页面权限，构建缓存需要的数据结构
        List<SystemMenuEntity> systemMenuEntities = new ArrayList<>();
        List<SystemFunctionEntity> systemFunctionEntities = new ArrayList<>();
        if (ObjectUtils.isNotNull(systemUserEntity.getType()) && systemUserEntity.getType().intValue() == UserTypeConstant.ADMIN.getType()) {
            systemMenuEntities.addAll(systemMenuDao.selectList(new QueryWrapper<SystemMenuEntity>().orderByAsc("sort_index")));
            systemFunctionEntities.addAll(systemFunctionDao.selectList(new QueryWrapper<SystemFunctionEntity>().orderByAsc("sort_index")));
        } else {
            List<SystemUserRoleEntity> systemUserRoleEntities = systemUserRoleDao.selectList(new QueryWrapper<SystemUserRoleEntity>().eq("user_id", systemUserEntity.getId()));
            for (SystemUserRoleEntity systemUserRoleEntity : systemUserRoleEntities) {
                List<SystemRoleMenuEntity> systemRoleMenuEntities = systemRoleMenuDao.selectList(new QueryWrapper<SystemRoleMenuEntity>().eq("role_id", systemUserRoleEntity.getRoleId()));
                for (SystemRoleMenuEntity systemRoleMenuEntity : systemRoleMenuEntities) {
                    systemMenuEntities.add(systemMenuDao.selectById(systemRoleMenuEntity.getMenuId()));
                }
                List<SystemRoleFunctionEntity> systemRoleFunctionEntities = systemRoleFunctionDao.selectList(new QueryWrapper<SystemRoleFunctionEntity>().eq("role_id", systemUserRoleEntity.getRoleId()));
                for (SystemRoleFunctionEntity systemRoleFunctionEntity : systemRoleFunctionEntities) {
                    systemFunctionEntities.add(systemFunctionDao.selectById(systemRoleFunctionEntity.getFunctionId()));
                }
            }
            systemMenuEntities = systemMenuEntities.stream().sorted(Comparator.comparing(systemMenuEntity -> systemMenuEntity.getSortIndex())).collect(Collectors.toList());
            systemFunctionEntities = systemFunctionEntities.stream().sorted(Comparator.comparing(systemFunctionEntity -> systemFunctionEntity.getSortIndex())).collect(Collectors.toList());
        }
        
        Map<Long, SystemMenuEntity> menuTreeMap = new LinkedHashMap<>();
        Map<String, String> menuMap = new LinkedHashMap<>();
        Map<String, String> functionMap = new LinkedHashMap<>();
        for (SystemMenuEntity systemMenuEntity : systemMenuEntities) {
            menuTreeMap.put(systemMenuEntity.getId(), systemMenuEntity);
            menuMap.put(systemMenuEntity.getCode(), systemMenuEntity.getName());
        }
        for (SystemFunctionEntity systemFunctionEntity : systemFunctionEntities) {
            functionMap.put(systemFunctionEntity.getCode(), systemFunctionEntity.getUrl());
        }
        
        List<SystemMenuEntity> menuTreeList = new ArrayList<>();
        
        for (SystemMenuEntity systemMenuEntity : systemMenuEntities) {
            
            SystemMenuEntity parentMenuEntity = menuTreeMap.get(systemMenuEntity.getParentId());
            if (ObjectUtils.isNull(parentMenuEntity)) {
                menuTreeList.add(systemMenuEntity);
            } else {
                parentMenuEntity.getTreeList().add(systemMenuEntity);
            }
            
        }
        
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        systemUserEntity.setPassword(null);
        cacheService.save(String.format(TokenConstant.TOKEN_USERINFO_KEY, token), JSON.toJSONString(systemUserEntity));
        cacheService.save(String.format(TokenConstant.TOKEN_MENU_KEY, token), JSON.toJSONString(menuMap));
        cacheService.save(String.format(TokenConstant.TOKEN_FUNCTION_KEY, token), JSON.toJSONString(functionMap));
        cacheService.save(String.format(TokenConstant.TOKEN_MENU_TREE_KEY, token), JSON.toJSONString(menuTreeList));
        
        Map<String, Object> data = new HashMap<>();
        //令牌
        data.put("token", token);
        //用户信息
        data.put("systemUser", systemUserEntity);
        //菜单集合
        data.put("systemMenuList", systemMenuEntities);
        //权限集合
        data.put("systemFunctionList", systemFunctionEntities);
        //菜单树
        data.put("menuTree", menuTreeList);
        
        return Result.ofData(data);
        
    }
    
    @Override
    public Result getAdminInfo(String token) {
        
        SystemCacheEntity systemCacheEntity = cacheService.get(String.format(TokenConstant.TOKEN_USERINFO_KEY, token));
        if (ObjectUtils.isNull(systemCacheEntity)) {
            return Result.ofErrors(BusinessException.noLogin());
        }
        
        return Result.ofData(systemCacheEntity.getValue());
        
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result tenantLogin(TenantLoginRequest tenantLoginRequest) {
        
        //验证登录名称
        List<TenantUserEntity> tenantUserEntities = tenantUserDao.selectList(new QueryWrapper<TenantUserEntity>().eq("username", tenantLoginRequest.getUsername()));
        if (CollectionUtils.isEmpty(tenantUserEntities)) {
            throw BusinessException.from("登录名称不存在或登录密码错误");
        }
        
        TenantUserEntity tenantUserEntity = tenantUserEntities.get(0);
        
        //验证登录密码
        if (!tenantUserEntity.getPassword().equals(MD5Utils.md5Hex(tenantLoginRequest.getPassword()))) {
            throw BusinessException.from("登录名称不存在或登录密码错误");
        }
        //验证状态
        if (tenantUserEntity.getStatus().intValue() == StatusConstant.DISABLE) {
            throw BusinessException.from("登录名称不存在或登录密码错误");
        }
        
        //查询登录用户拥有的菜单页面权限，构建缓存需要的数据结构
        List<TenantMenuEntity> tenantMenuEntities = new ArrayList<>();
        List<TenantTenantMenuEntity> tenantTenantMenuEntities = tenantTenantMenuDao.selectList(new QueryWrapper<TenantTenantMenuEntity>().eq("tenant_id", tenantUserEntity.getTenantId()));
        for (TenantTenantMenuEntity tenantTenantMenuEntity : tenantTenantMenuEntities) {
            tenantMenuEntities.add(tenantMenuDao.selectById(tenantTenantMenuEntity.getMenuId()));
        }
        tenantMenuEntities = tenantMenuEntities.stream().sorted(Comparator.comparing(tenantMenuEntity -> tenantMenuEntity.getSortIndex())).collect(Collectors.toList());
        
        List<TenantFunctionEntity> tenantFunctionEntities = new ArrayList<>();
        List<TenantTenantFunctionEntity> tenantTenantFunctionEntities = tenantTenantFunctionDao.selectList(new QueryWrapper<TenantTenantFunctionEntity>().eq("tenant_id", tenantUserEntity.getTenantId()));
        for (TenantTenantFunctionEntity tenantTenantFunctionEntity : tenantTenantFunctionEntities) {
            tenantFunctionEntities.add(tenantFunctionDao.selectById(tenantTenantFunctionEntity.getFunctionId()));
        }
        tenantFunctionEntities = tenantFunctionEntities.stream().sorted(Comparator.comparing(tenantFunctionEntity -> tenantFunctionEntity.getSortIndex())).collect(Collectors.toList());
        
        Map<Long, TenantMenuEntity> menuTreeMap = new LinkedHashMap<>();
        Map<String, String> menuMap = new LinkedHashMap<>();
        Map<String, String> functionMap = new LinkedHashMap<>();
        for (TenantMenuEntity tenantMenuEntity : tenantMenuEntities) {
            menuTreeMap.put(tenantMenuEntity.getId(), tenantMenuEntity);
            menuMap.put(tenantMenuEntity.getCode(), tenantMenuEntity.getName());
        }
        for (TenantFunctionEntity tenantFunctionEntity : tenantFunctionEntities) {
            functionMap.put(tenantFunctionEntity.getCode(), tenantFunctionEntity.getUrl());
        }
        
        List<TenantMenuEntity> menuTreeList = new ArrayList<>();
        
        for (TenantMenuEntity tenantMenuEntity : tenantMenuEntities) {
            
            TenantMenuEntity parentMenuEntity = menuTreeMap.get(tenantMenuEntity.getParentId());
            if (ObjectUtils.isNull(parentMenuEntity)) {
                menuTreeList.add(tenantMenuEntity);
            } else {
                parentMenuEntity.getTreeList().add(tenantMenuEntity);
            }
            
        }
        
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        tenantUserEntity.setPassword(null);
        cacheService.save(String.format(TokenConstant.TOKEN_TENANT_KEY, token), JSON.toJSONString(tenantUserEntity));
        cacheService.save(String.format(TokenConstant.TOKEN_MENU_KEY, token), JSON.toJSONString(menuMap));
        cacheService.save(String.format(TokenConstant.TOKEN_FUNCTION_KEY, token), JSON.toJSONString(functionMap));
        cacheService.save(String.format(TokenConstant.TOKEN_MENU_TREE_KEY, token), JSON.toJSONString(menuTreeList));
        
        Map<String, Object> data = new HashMap<>();
        //令牌
        data.put("token", token);
        //用户信息
        data.put("tenantUser", tenantUserEntity);
        //菜单集合
        data.put("tenantMenuList", tenantMenuEntities);
        //权限集合
        data.put("tenantFunctionList", tenantFunctionEntities);
        //菜单树
        data.put("menuTree", menuTreeList);
        
        return Result.ofData(data);
        
    }
    
    @Override
    public Result getTenantInfo(String token) {
        
        SystemCacheEntity systemCacheEntity = cacheService.get(String.format(TokenConstant.TOKEN_TENANT_KEY, token));
        
        if (ObjectUtils.isNull(systemCacheEntity)) {
            return Result.ofErrors(BusinessException.noLogin());
        }
        
        return Result.ofData(systemCacheEntity.getValue());
        
    }
    
}
